From b3e1db42b4dbb5f99705e4d1057ca49b44f4f5ee Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 27 Oct 2025 01:00:00 +0100 Subject: [PATCH] odhcp6c: fix safe interval processing to follow RFC 4862 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This resolves an issue occuring in combination with Fritz! upstream routers that send old prefixes with a valid time of zero for a long time. Before this change, they were with each received RA extended to two hours if the prefix was already known before. Signed-off-by: Jonas Lochmann Link: https://github.com/openwrt/odhcp6c/pull/108 Signed-off-by: Álvaro Fernández Rojas --- src/odhcp6c.c | 55 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/src/odhcp6c.c b/src/odhcp6c.c index b66c5c3..cf786e4 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -942,20 +942,61 @@ bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new, uint32_t safe, unsigned int holdoff_interval) { struct odhcp6c_entry *x = odhcp6c_find_entry(state, new); - - if (x && x->valid > new->valid && new->valid < safe) - new->valid = safe; + uint32_t new_valid; + + /* + * "safe" refers to https://www.rfc-editor.org/rfc/rfc4862#section-5.5.3 + * section e; it is either the two hours in seconds or zero when (e) + * does not apply. + * + * The base condition for applying safe is that there is already a + * matching prefix (and safe itself must be set). + */ + if (safe && x) { + if (new->valid > safe || new->valid > x->valid) { + /* + * 1: If the received Valid Lifetime is greater than 2 hours or + * greater than RemainingLifetime, set the valid lifetime of the + * corresponding address to the advertised Valid Lifetime. + */ + new_valid = new->valid; + } else if (x->valid <= safe) { + /* + * 2: If RemainingLifetime is less than or equal + * to 2 hours, ignore the Prefix Information option with + * regards to the valid lifetime, unless the Router + * Advertisement from which this option was obtained has + * been authenticated (e.g., via Secure Neighbor + * Discovery [RFC3971]). If the Router Advertisement + * was authenticated, the valid lifetime of the + * corresponding address should be set to the Valid + * Lifetime in the received option. + * + * Since authenticated advertisements aren't supported we + * always keep the old value. + */ + new_valid = x->valid; + } else { + /* + * 3: Otherwise, reset the valid lifetime of the corresponding + * address to 2 hours. + */ + new_valid = safe; + } + } else { + new_valid = new->valid; + } if (x) { - if (holdoff_interval && new->valid >= x->valid && - new->valid != UINT32_MAX && - new->valid - x->valid < holdoff_interval && + if (holdoff_interval && new_valid >= x->valid && + new_valid != UINT32_MAX && + new_valid - x->valid < holdoff_interval && new->preferred >= x->preferred && new->preferred != UINT32_MAX && new->preferred - x->preferred < holdoff_interval) return false; - x->valid = new->valid; + x->valid = new_valid; x->preferred = new->preferred; x->t1 = new->t1; x->t2 = new->t2; -- 2.30.2